﻿#if EGOAL
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using EgoalTech.DB;

namespace EgoalTech.MTrade.Query
{
    public class ObjectDataContext : IDisposable
    {
        #region IDbConnection Wrap
        public class ConnectionWrap : IDbConnection
        {
            private IDbConnection source;

            public ConnectionWrap(IDbConnection source)
            {
                this.source = source;
            }

            void IDisposable.Dispose()
            {
                source.Dispose();
            }

            IDbTransaction IDbConnection.BeginTransaction()
            {
                return source.BeginTransaction();
            }

            IDbTransaction IDbConnection.BeginTransaction(IsolationLevel il)
            {
                return source.BeginTransaction(il);
            }

            void IDbConnection.Close()
            {
                source.Close();
            }

            void IDbConnection.ChangeDatabase(string databaseName)
            {
                source.ChangeDatabase(databaseName);
            }

            IDbCommand IDbConnection.CreateCommand()
            {
                var command = source.CreateCommand();
                return new CommandWrap(this, command);
            }

            void IDbConnection.Open()
            {
                source.Open();
            }

            string IDbConnection.ConnectionString
            {
                get { return source.ConnectionString; }
                set { source.ConnectionString = value; }
            }

            int IDbConnection.ConnectionTimeout
            {
                get { return source.ConnectionTimeout; }
            }

            string IDbConnection.Database
            {
                get { return source.Database; }
            }

            ConnectionState IDbConnection.State
            {
                get { return source.State; }
            }
        }

        class CommandWrap : IDbCommand
        {
            private IDbCommand source;
            private ConnectionWrap connection;

            public CommandWrap(ConnectionWrap connection, IDbCommand source)
            {
                this.source = source;
                this.connection = connection;
            }

            void IDisposable.Dispose()
            {
                source.Dispose();
            }

            void IDbCommand.Prepare()
            {
                source.Prepare();
            }

            void IDbCommand.Cancel()
            {
                source.Cancel();
            }

            IDbDataParameter IDbCommand.CreateParameter()
            {
                return source.CreateParameter();
            }

            int IDbCommand.ExecuteNonQuery()
            {
                return source.ExecuteNonQuery();
            }

            IDataReader IDbCommand.ExecuteReader()
            {
                return source.ExecuteReader();
            }

            IDataReader IDbCommand.ExecuteReader(CommandBehavior behavior)
            {
                return source.ExecuteReader(behavior);
            }

            object IDbCommand.ExecuteScalar()
            {
                return source.ExecuteScalar();
            }

            IDbConnection IDbCommand.Connection
            {
                get { return this.connection; }
                set { this.connection = (ConnectionWrap)value; }
            }

            IDbTransaction IDbCommand.Transaction
            {
                get { return source.Transaction; }
                set { source.Transaction = value; }
            }

            string IDbCommand.CommandText
            {
                get { return source.CommandText; }
                set { source.CommandText = value; }
            }

            int IDbCommand.CommandTimeout
            {
                get { return source.CommandTimeout; }
                set { source.CommandTimeout = value; }
            }

            CommandType IDbCommand.CommandType
            {
                get { return source.CommandType; }
                set { source.CommandType = value; }
            }

            IDataParameterCollection IDbCommand.Parameters
            {
                get { return source.Parameters; }
            }

            UpdateRowSource IDbCommand.UpdatedRowSource
            {
                get { return source.UpdatedRowSource; }
                set { source.UpdatedRowSource = value; }
            }
        }
        #endregion

        private DataContext queryContext;

        public ObjectDataContext(Assembly modelsAssembly, string connection)
        {
            var mappingSource = CreateMappingSource(modelsAssembly);
            this.queryContext = new DataContext(connection, mappingSource);
        }

        public ObjectDataContext(Assembly modelsAssembly, DbObjectOperator op)
        {
            var mappingSource = CreateMappingSource(modelsAssembly);
            var conn = op.DbOperator.Connection;// new ConnectionWrap(op.DbOperator.Connection);
            this.queryContext = new DataContext(conn, mappingSource);
           
        }

        MappingSource CreateMappingSource(Assembly modelsAssembly)
        {
            var entityTypes = modelsAssembly.GetTypes();

            var sb = new StringBuilder();
            sb.AppendFormat("<Database Name=\"{0}\" Provider=\"System.Data.Linq.SqlClient.Sql2008Provider\" xmlns=\"http://schemas.microsoft.com/linqtosql/mapping/2007\">", this.GetType().Name);

            foreach (var type in entityTypes)
            {
                var attr = type.GetCustomAttributes(true).OfType<QueryTableAttribute>().SingleOrDefault();
                if (attr == null)
                    continue;

                sb.AppendFormat("<Table Name=\"{0}\">", attr.TableName);
                sb.AppendLine();

                sb.AppendFormat("<Type Name=\"{0}\" >", type.FullName);
                sb.AppendLine();

                var properties = type.GetProperties();
                foreach (var property in properties)
                {
                    var colAttr = property.GetCustomAttributes(true).OfType<DataFieldAttribute>().SingleOrDefault();
                    if (colAttr != null)
                    {
                        sb.AppendFormat("<Column Name=\"{0}\" IsPrimaryKey=\"{1}\" Member=\"{2}\"/>",
                                        colAttr.DataFieldName, colAttr.PrimaryKey, property.Name);
                        sb.AppendLine();
                    }
                }

                sb.AppendLine("</Type>");
                sb.AppendLine("</Table>");
            }

            sb.AppendLine("</Database>");

            var mappingSource = XmlMappingSource.FromXml(sb.ToString());
            return mappingSource;
        }



        public IQueryable GetTable(Type entityType)
        {
            return queryContext.GetTable(entityType);
        }

        public IQueryable<T> GetTable<T>() where T : class
        {
            return queryContext.GetTable<T>();
        }

        public TextWriter Log
        {
            get { return this.queryContext.Log; }
            set { this.queryContext.Log = value; }
        }

        void IDisposable.Dispose()
        {
            if (this.queryContext != null)
            {
                queryContext.Dispose();
            }
        }
    }
}
#endif
